package sso.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import sso.util.JwtUtils;
import sso.util.WebUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
//1.系统启动时,要进行配置会访问SecurityConfig.
//2.客户端访问时,还是先访问service/UserDetailServiceImpl
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
      return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        //1.关闭跨域攻击
        http.csrf().disable();
        //2.配置form认证
         http.formLogin()
                 //登录成功怎么处理(向客户端返回json)
                 .successHandler(successHandler())//成功
                 //登录失败怎么处理?(向客户端返回json)
                 .failureHandler(failureHandler());//失败
        //假如某个资源必须认证才可访问,那没有认证怎么办?
        http.exceptionHandling()
                .authenticationEntryPoint(entryPoint());//提示要认证
//                .accessDeniedHandler(null);//提示访问被拒绝
        //3.所有资源都要认证
        http.authorizeRequests().anyRequest().authenticated();
    }
    //登录成功以后的处理器
    private AuthenticationSuccessHandler successHandler(){
            return (request, response, authentication) -> {
                HashMap<String, Object> map = new HashMap<>();
                    map.put("state",200);
                    map.put("message","login ok");
                    //思考除了返回这些信息,还要返回什么?(JWT令牌)
                //创建一个令牌对象,JWT格式的令牌可以满足这个要求
                HashMap<String, Object> jwtMap = new HashMap<>();
                //获取用户对象,此对象为登录成功以后封装了登录信息的对象
                User principal = (User) authentication.getPrincipal();
                //获取用户权限封装到jwtMap中
                jwtMap.put("username",principal.getUsername());//登录用户
                ArrayList<Object> authoritiesList = new ArrayList<>();
                Collection<GrantedAuthority> as = principal.getAuthorities();
                for(GrantedAuthority a:as){
                    authoritiesList.add(a.getAuthority());
                }
                //上面遍历的新方式
//                user.getAuthorities().forEach((authority)->{
//                        authorities.add(authority.getAuthority());
//
//                });
                jwtMap.put("authorities",authoritiesList);//[sys:res:retrieve,sys:res:create]
                //创建token
                String token = JwtUtils.generatorToken(jwtMap);
                    map.put("token",token);
                    WebUtils.writeJsonToClient(response,map);
            };
    }
    //登录失败的处理器
    private AuthenticationFailureHandler failureHandler(){
            return  ( request,  response,  authException) ->{//lambda 表达式
                HashMap<String, Object> map = new HashMap<>();
                map.put("state",500);
                map.put("message","username or password error");
                try {
                    WebUtils.writeJsonToClient(response,map);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
    }
    //假如没有登录访问资源时
    private AuthenticationEntryPoint entryPoint(){
        return ( request, response, authException) ->{
            HashMap<String, Object> map = new HashMap<>();
            map.put("state",500);
            map.put("message","please Login");
            //思考除了返回这些信息,还有返回什么?(JWT令牌)
            WebUtils.writeJsonToClient(response,map);
        };
    }

}
